// attract positive repel negative

package codeanticode.clphysics;

public class Attraction implements Force {
  Particle a;
  Particle b;
  float k;
  boolean on;
  float distanceMin;
  float distanceMinSquared;

  public Attraction(Particle a, Particle b, float k, float distanceMin) {
    this.a = a;
    this.b = b;
    this.k = k;
    on = true;
    this.distanceMin = distanceMin;
    this.distanceMinSquared = distanceMin * distanceMin;
  }

  protected void setA(Particle p) {
    a = p;
  }

  protected void setB(Particle p) {
    b = p;
  }

  public final float getMinimumDistance() {
    return distanceMin;
  }

  public final void setMinimumDistance(float d) {
    distanceMin = d;
    distanceMinSquared = d * d;
  }

  public final void turnOff() {
    on = false;
  }

  public final void turnOn() {
    on = true;
  }

  public final void setStrength(float k) {
    this.k = k;
  }

  public final Particle getOneEnd() {
    return a;
  }

  public final Particle getTheOtherEnd() {
    return b;
  }

  public void apply() {
    if (on && (a.isFree() || b.isFree())) {
      float a2bX = a.position().x() - b.position().x();
      float a2bY = a.position().y() - b.position().y();
      float a2bZ = a.position().z() - b.position().z();

      float a2bDistanceSquared = a2bX * a2bX + a2bY * a2bY + a2bZ * a2bZ;

      if (a2bDistanceSquared < distanceMinSquared)
        a2bDistanceSquared = distanceMinSquared;

      float force = k * a.mass * b.mass / a2bDistanceSquared;

      float length = (float) Math.sqrt(a2bDistanceSquared);

      // make unit vector

      a2bX /= length;
      a2bY /= length;
      a2bZ /= length;

      // multiply by force

      a2bX *= force;
      a2bY *= force;
      a2bZ *= force;

      // apply

      if (a.isFree())
        a.force().add(-a2bX, -a2bY, -a2bZ);
      if (b.isFree())
        b.force().add(a2bX, a2bY, a2bZ);
    }
  }

  public final float getStrength() {
    return k;
  }

  public final boolean isOn() {
    return on;
  }

  public final boolean isOff() {
    return !on;
  }
}
